/*
 * C++11引入了std::promise和std::future两个类，用于实现异步编程。
 * std::promise用于在某一线程中设置某个值或异常，而std::future则用于在另一线程中获取这个值或异常。
 */

#include <iostream>
#include <thread>
#include <future>
#include <unistd.h>

void set_value1(std::promise<std::string> prom)
{
    std::this_thread::sleep_for(std::chrono::seconds(5));
    // 设置 promise 的值
    prom.set_value("I am promise1");
}

void set_value2(std::promise<std::string> prom)
{
    std::this_thread::sleep_for(std::chrono::seconds(5));
    // 设置 promise 的值
    prom.set_value("I am promise2");
}

void true_use()
{
    // 每个 promise 对应一个独立的 future
    std::promise<std::string> prom1, prom2;
    std::future<std::string> fut1 = prom1.get_future();
    std::future<std::string> fut2 = prom2.get_future();

    std::thread t1(set_value1, std::move(prom1)); // 移动 prom1
    std::thread t2(set_value2, std::move(prom2)); // 移动 prom2

    std::cout << "Value1: " << fut1.get() << '\n'; // 等待线程1
    std::cout << "Value2: " << fut2.get() << '\n'; // 等待线程2

    t1.join();
    t2.join();
}

void error_use()
{
    // 创建一个 promise 对象
    std::promise<std::string> prom;
    // 获取与 promise 相关联的 future 对象
    std::future<std::string> fut = prom.get_future();
    // 在新 thread 设置promise的值

    // 这个就是标准的错误，prom的使用权已经完全给了第一个线程
    std::thread t1(set_value1, std::move(prom));
    std::thread t2(set_value2, std::move(prom));

    // 在主线程中获取 future 的值
    std::cout << "Waiting for the thread to set the value...\n";
    std::cout << "Value set by the thread: " << fut.get() << '\n';

    t1.join();
    t2.join();
}

/*
  std::promise还有一个set_exception()方法，用于设置异常。
  该方法接受一个std::exception_ptr参数，该参数可以通过调用std::current_exception()方法获取
*/
void set_exception(std::promise<void> prom)
{
    try
    {
        // 输出一个异常
        throw std::runtime_error("An error ocurred");
    }
    catch (...)
    {
        // 设置promise异常
        prom.set_exception(std::current_exception());
    }
}

void exception_use()
{
    std::promise<void> prom;
    std::future<void> fut = prom.get_future();
    // 在新 thread 中设置 promise 的异常
    std::thread t(set_exception, std::move(prom));
    // 在主线程获取future异常
    try
    {
        std::cout << "Waiting for the thread to set the exception...\n";
        fut.get(); // 会重新抛出线程中的异常
    }
    catch (const std::exception &e)
    {
        std::cout << "Exception set by the thread: " << e.what() << '\n';
    }
    t.join();
}

int main()
{
    exception_use();
    // error_use();
    // true_use();
    return 0;
}

/*
    std::promise 是不可复制的，只能移动
    std::promise 禁用了拷贝构造函数和拷贝赋值运算符（= delete），但提供了移动语义。

    这是因为它管理的“共享状态”（future 获取的结果）必须唯一，不能多份共存。

    如果允许拷贝，多个 promise 可能同时修改共享状态，导致数据竞争
*/